{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "<a id='HOME'></a>\n",
    "# CHAPTER 6 Oh Oh: Objects and Classes\n",
    "## 物件與類別\n",
    "\n",
    "* [6.1 什麼是物件](#Objects)\n",
    "* [6.2 使用class定義類別](#Class)\n",
    "* [6.3 繼承](#Inheritance)\n",
    "* [6.4 覆蓋方法](#Override)\n",
    "* [6.5 添加新方法](#Add)\n",
    "* [6.6 使用super得到父類別支援](#super)\n",
    "* [6.7 self](#self)\n",
    "* [6.8 設置與呼叫特性的屬性](#Attribute)\n",
    "* [6.9 使用名稱重整保持私有性](#Privacy)\n",
    "* [6.10 方法的類別](#Types)\n",
    "* [6.11 鴨子類別](#Duck)\n",
    "* [6.12 特殊方法](#Special)\n",
    "* [6.13 組合](#Composition)\n",
    "* [6.14 類別與對象v.s.模組](#ClassesModules)\n",
    "\n",
    "\n",
    "\n",
    "除了python內建的對象，我們也可以通過class來建立屬於自己的類別供使用"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "<a id='Objects'></a>\n",
    "## 6.1 什麼是物件\n",
    "[回目錄](#HOME)\t\t\t\t\t \n",
    "\n",
    "\n",
    "第二章節提到，python裡面所有的東西都是物件(_objects_)，連同一個整數也是一種物件，python的語法設計可以巧妙的隱藏諸多細節\n",
    "\n",
    "本章節將會介紹到自訂新的物件以及修改現有的物件。\n",
    "\n",
    "物件包含屬性(__attribute__)與方法(__methods__)，  \n",
    "例如整數5和7都是整數物件，都包含了基本的+-\\*/方法，  \n",
    "'cat' 和 'duck'都是字串物件，都包含了 __capitalize()__ 和 __replace()__ 兩種方法\n",
    "\n",
    "所以當你要創造一個新的物件時，就必須先定義一個類別，用它來清楚規範其類別可以創造出來的物件有什麼樣的屬性(__attribute__)與方法(__methods__)\n",
    "\n",
    "物件像名詞，方法就像個動詞。對象代表一個獨立的事物，方法用來定義她如何與其他事物相互作用  \n",
    "與模組不同的是，你可以同時創建多個同類別的物件，他們之間的屬性值可能各有不同，對象像是個結構，包含著數據。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "<a id='Class'></a>\n",
    "## 6.2 使用class定義類別\n",
    "[回目錄](#HOME)\t\t\t \n",
    "\t \n",
    "我們可以通過class來定義自己的類別，就可以創造出新的物件\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Elmer Fudd\n",
      "QQ@WW.tw\n",
      "I am Elmer Fudd!!!\n",
      "Hsuky\n",
      "XDD@WW.tw\n"
     ]
    }
   ],
   "source": [
    "# 自定義一個Person()\n",
    "# __init__為定義屬性部分\n",
    "# self為物件自己\n",
    "\n",
    "class Person():\n",
    "    def __init__(self, name, email):\n",
    "        self.name = name\n",
    "        self.email = email\n",
    "        \n",
    "    def XDD(self, tem):\n",
    "        return 'I am ' + self.name + tem\n",
    "\n",
    "hunter = Person('Elmer Fudd', \"QQ@WW.tw\")\n",
    "\n",
    "Husky = Person('Hsuky', \"XDD@WW.tw\")\n",
    "\n",
    "print(hunter.name)\n",
    "print(hunter.email)\n",
    "\n",
    "print(hunter.XDD('!!!'))\n",
    "\n",
    "print(Husky.name)\n",
    "print(Husky.email)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "<a id='Inheritance'></a>\n",
    "## 6.3 繼承\n",
    "[回目錄](#HOME)\t\t\t\t\t\t\t \n",
    "\n",
    "在編寫類別時，如果發現已經有前人開發過，那就可以不用整段複製，可以採用繼承的方法取得他的屬性與方法  \n",
    "並且補充自己會用到的功能，一方面可以減少去改既有的類別辛苦，也可省去複製貼上的功"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "add: 4\n",
      "add: 6\n"
     ]
    }
   ],
   "source": [
    "class math():\n",
    "    def add(self, a, b):\n",
    "        print(\"add:\", a + b)\n",
    "\n",
    "class mean(math):\n",
    "    pass\n",
    "    \n",
    "ab = mean()\n",
    "ab.add(1, 3)\n",
    "\n",
    "ac = math()\n",
    "ac.add(1,5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "<a id='#Override'></a>\n",
    "## 6.4 覆蓋方法\n",
    "[回目錄](#HOME) \n",
    "\n",
    "當然我們也可以覆蓋掉原有的方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "add: 7\n"
     ]
    }
   ],
   "source": [
    "class math():\n",
    "    def add(self, a, b):\n",
    "        print(\"add:\", a + b)\n",
    "\n",
    "class mean(math):\n",
    "    def add(self, a, b):\n",
    "        print(\"add:\", a + b + b)\n",
    "    \n",
    "ab = mean()\n",
    "ab.add(1, 3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "<a id='#Add'></a>\n",
    "## 6.5 添加新方法\n",
    "[回目錄](#HOME) \n",
    "\n",
    "前面的都是複製與修改接著我們也可以在新的類別中加入新的方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "add: 4\n",
      "add: -2\n",
      "add: 6\n"
     ]
    }
   ],
   "source": [
    "class math():\n",
    "    def add(self, a, b):\n",
    "        print(\"add:\", a + b)\n",
    "\n",
    "class mean(math):\n",
    "    def less(self, a, b):\n",
    "        print(\"add:\", a - b)\n",
    "    \n",
    "ab = mean()\n",
    "ab.add(1, 3)\n",
    "ab.less(1, 3)\n",
    "\n",
    "ac = math()\n",
    "ac.add(1, 5)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "<a id='super'></a>\n",
    "## 6.6 使用super得到父類別支援\n",
    "[回目錄](#HOME) \n",
    "\n",
    "那如果們我要修改屬性部分( *\\_\\_int\\_\\_* )，除了直接重寫一個蓋掉以外還有__super()__方法可以用來擴充既有的屬性，這樣才有達到既成的目的"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Elmer Fudd\n",
      "QQ@CC.tw\n",
      "=============\n",
      "Elmer Fudd\n",
      "QQ@CC.tw\n",
      "2016/05/07\n"
     ]
    }
   ],
   "source": [
    "class Person():\n",
    "    def __init__(self, name, email):\n",
    "        self.name = name\n",
    "        self.email = email\n",
    "        \n",
    "class Person_day(Person):\n",
    "    def __init__(self, name, email, birthday):\n",
    "        super().__init__(name, email)\n",
    "        self.birthday = birthday\n",
    "        \n",
    "        \n",
    "hunter = Person('Elmer Fudd', 'QQ@CC.tw')\n",
    "husky = Person_day('Elmer Fudd', 'QQ@CC.tw', '2016/05/07')\n",
    "\n",
    "print(hunter.name)\n",
    "print(hunter.email)\n",
    "print('=============')\n",
    "print(husky.name)\n",
    "print(husky.email)\n",
    "print(husky.birthday)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "<a id='self'></a>\n",
    "## 6.7 self\n",
    "[回目錄](#HOME) \n",
    "\n",
    "在定義屬性時常常會看到__self__，__self__指的就是被創造出來的物件它自身。  \n",
    "所以在__\\_\\_int\\_\\_(self, name)__的參數部分，實際在__self__並不用傳入參數。\n",
    "\n",
    "```python\n",
    "class Person():\n",
    "    def __init__(self, name, email):\n",
    "        self.name = name\n",
    "        self.email = email\n",
    "\n",
    "XDD = Person('QQ', 'QQ@gmail.com')  #不須傳入self參數\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "<a id='Attribute'></a>\n",
    "## 6.8 設置與呼叫特性的屬性\n",
    "[回目錄](#HOME) \n",
    "\n",
    "在其他語言中，可以設置__getter__ 和 __setter__來確保私有屬性的讀寫，但是在python一切都是公開的，  \n",
    "可以透過__property()__來達到python風格的寫法，即可將屬性值藏起來，不用透過呼叫每個__getter()__和__setter()__來達到改變斯有變數  \n",
    "\n",
    "若沒有給定setter函數，則無法透過__property()__來改變屬性質，當然前提是在別人不知道實在儲存變數的屬性名稱是什麼"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "提取名稱時，則呼叫get函數\n",
      "---使用get函數---\n",
      "Howard!!\n",
      "\n",
      "設定名稱時，則呼叫set函數\n",
      "---使用set函數---\n",
      "nname被改成Daffy\n",
      "---使用get函數---\n",
      "Daffy??!!\n",
      "\n",
      "當然也可以透過原始的set_name()與get_name()進行修改私有屬性\n",
      "---使用get函數---\n",
      "Daffy??!!\n",
      "---使用set函數---\n",
      "---使用get函數---\n",
      "Daffyyyy??!!\n"
     ]
    }
   ],
   "source": [
    "class Duck():\n",
    "    def __init__(self, input_name):\n",
    "        self.hidden_name = input_name\n",
    "    \n",
    "    #取的 name 的函數\n",
    "    def get_name(self):\n",
    "        print('---使用get函數---')\n",
    "        return self.hidden_name + '!!'\n",
    "    \n",
    "    #設定 name 的函數\n",
    "    def set_name(self, input_name):\n",
    "        print('---使用set函數---')\n",
    "        self.hidden_name = input_name + '??'\n",
    "    \n",
    "    #使用property(get,set)來包裝，讓使用上更方便\n",
    "    name = property(get_name, set_name)\n",
    "\n",
    "#宣告物件為Duck類別，並給定name，從頭到尾都沒有直接抄作hidden_name來改變屬性值\n",
    "fowl = Duck('Howard')\n",
    "print('提取名稱時，則呼叫get函數')\n",
    "print(fowl.name)\n",
    "\n",
    "print('\\n設定名稱時，則呼叫set函數')\n",
    "fowl.name = 'Daffy'\n",
    "print('nname被改成Daffy')\n",
    "print(fowl.name)\n",
    "\n",
    "print('\\n當然也可以透過原始的set_name()與get_name()進行修改私有屬性')\n",
    "print(fowl.get_name())\n",
    "fowl.set_name('Daffyyyy')\n",
    "print(fowl.get_name())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "提取名稱時，則呼叫get函數\n",
      "---使用get函數---\n",
      "Howard\n",
      "\n",
      "設定名稱時，則呼叫set函數\n",
      "---使用set函數---\n",
      "nname被改成Daffy\n",
      "---使用get函數---\n",
      "Daffy\n"
     ]
    }
   ],
   "source": [
    "#當然可以透過裝飾器，來寫得更漂亮!!!\n",
    "\n",
    "class Duck():\n",
    "    def __init__(self, input_name):\n",
    "        self.hidden_name = input_name\n",
    "    \n",
    "    @property\n",
    "    def name(self):\n",
    "        print('---使用get函數---')\n",
    "        return self.hidden_name\n",
    "\n",
    "    @name.setter\n",
    "    def name(self, input_name):\n",
    "        print('---使用set函數---')\n",
    "        self.hidden_name = input_name\n",
    "        \n",
    "#宣告物件為Duck類別，並給定name\n",
    "fowl = Duck('Howard')\n",
    "\n",
    "print('提取名稱時，則呼叫get函數')\n",
    "print(fowl.name)\n",
    "\n",
    "print('\\n設定名稱時，則呼叫set函數')\n",
    "fowl.name = 'Daffy'\n",
    "print('nname被改成Daffy')\n",
    "print(fowl.name)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "<a id='Privacy'></a>\n",
    "## 6.9 使用名稱重整保持私有性\n",
    "[回目錄](#HOME) \n",
    "\n",
    "前面的用法如果被知道實際儲存屬性的名稱為什麼，也是可以對其修改\n",
    "所以可以透過名稱重整來把實際儲存屬性的名稱改寫\n",
    "\n",
    "在屬性名稱前面加上( \\_\\_ )來重整名稱，雖然不能完全的防止修改私有屬性，但可以透過有效的方法降低有意或無意的修改"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "---使用get函數---\n",
      "Howard\n",
      "---使用set函數---\n",
      "---使用get函數---\n",
      "Donald\n"
     ]
    }
   ],
   "source": [
    "class Duck():\n",
    "    def __init__(self, input_name):\n",
    "        self.__name = input_name\n",
    "    \n",
    "    @property\n",
    "    def name(self):\n",
    "        print('---使用get函數---')\n",
    "        return self.__name\n",
    "    \n",
    "    @name.setter\n",
    "    def name(self, input_name):\n",
    "        print('---使用set函數---')\n",
    "        self.__name = input_name\n",
    "\n",
    "        \n",
    "        \n",
    "fowl = Duck('Howard')\n",
    "print(fowl.name)\n",
    "fowl.name = 'Donald'\n",
    "print(fowl.name)\n",
    "\n",
    "#fowl.__name        #直接修改會錯誤\n",
    "#fowl._Duck__name   #重整完的名稱"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "<a id='Types'></a>\n",
    "## 6.10 方法的類別\n",
    "[回目錄](#HOME) \n",
    "\n",
    "前述交的都是物件的方法，對於類別本身也是可以設定屬性以及方法  \n",
    "分別使用 __類別.屬性__ 以及 __@classmethod__\n",
    "\n",
    "在類別的方法中，呼叫自己使用 __cls__ 或是 **類別名稱** 皆可以\n",
    "\n",
    "還有一種 __@staticmethod__ 可以設定類別的函數，差異在於  \n",
    "* @staticmethod不需使用cls參數\n",
    "* @classmethod第一個參數需為cls參數\n",
    "\n",
    "在使用上來說，若__@staticmethod__要調用到這個類別的屬性只能直接用名稱來取得，而__@classmethod__因為有cls參數傳入，所以可以透過cls來調用類別函數\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A has 3 little objects.\n",
      "A has 3 little objects.\n",
      "This CoyoteWeapon has been brought to you by Acme\n"
     ]
    }
   ],
   "source": [
    "class A():\n",
    "    count = 0           #類別的屬性\n",
    "    def __init__(self):\n",
    "        A.count += 1    #修改類別的屬性\n",
    "    \n",
    "    def exclaim(self):\n",
    "        print(\"I'm an A!\")\n",
    "    \n",
    "    @classmethod        #類別的方法(methond)\n",
    "    def kids(cls):\n",
    "        print(\"A has\", cls.count, \"little objects.\")\n",
    "        \n",
    "    @classmethod        #類別的方法(methond)\n",
    "    def kids2(A):\n",
    "        print(\"A has\", A.count, \"little objects.\")\n",
    "\n",
    "easy_a = A()\n",
    "breezy_a = A()\n",
    "wheezy_a = A()\n",
    "A.kids()\n",
    "A.kids2()\n",
    "\n",
    "\n",
    "class CoyoteWeapon():\n",
    "    @staticmethod\n",
    "    def commercial():\n",
    "        print('This CoyoteWeapon has been brought to you by Acme')\n",
    "        \n",
    "CoyoteWeapon.commercial()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "<a id='Duck'></a>\n",
    "## 6.11 鴨子類別\n",
    "[回目錄](#HOME) \n",
    "\n",
    "在物件導向的語言中多態(polymorphism)的使用，可以讓我們更方便的調用物件的函數\n",
    "\n",
    "不用管物件本身的類別是什麼，只要擁有相同的方法就可以呼叫到\n",
    "\n",
    "\n",
    "鴨子一詞的由來為，如果能像鴨子一樣叫，像鴨子一樣走路，那他就是一隻鴨子。  \n",
    "所以我們不用太在意是什麼物件，只要他能夠有一樣的方法可以使用，那我們就可以安心的使用了"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false,
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Elmer Fudd says I'm hunting wabbits.\n",
      "Brook says Babble\n"
     ]
    }
   ],
   "source": [
    "class Quote():\n",
    "    def __init__(self, person, words):\n",
    "        self.person = person\n",
    "        self.words = words\n",
    "    \n",
    "    def who(self):\n",
    "        return self.person\n",
    "\n",
    "    def says(self):\n",
    "        return self.words + '.'\n",
    "    \n",
    "class BabblingBrook():\n",
    "    def who(self):\n",
    "        return 'Brook'\n",
    "    \n",
    "    def says(self):\n",
    "        return 'Babble'\n",
    "    \n",
    "hunter = Quote('Elmer Fudd', \"I'm hunting wabbits\")\n",
    "brook = BabblingBrook()\n",
    "\n",
    "#儘管兩者完全獨立沒有關係，但只要有相同名稱的函數就可以呼叫到\n",
    "def who_says(obj):\n",
    "    print(obj.who(), 'says', obj.says())\n",
    "    \n",
    "who_says(hunter)\n",
    "who_says(brook)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "<a id='Special'></a>\n",
    "## 6.12 特殊方法\n",
    "[回目錄](#HOME) \n",
    "\n",
    "在python中，存在一些特殊方法( special method )或者稱回( magic method )，  \n",
    "這些方法為雙底線( **\\_\\_** )開頭與結束用法，前面介紹過的( **\\_\\_init\\_\\_** )就是一個特殊方法，他是用來對新物件初始化用\n",
    "\n",
    "假設我有一隻class裡面有個method可以用來判斷兩個字串的小寫是否相同\n",
    "\n",
    "```python\n",
    "#---------------採用一般方法寫法\n",
    "class Word():\n",
    "    def __init__(self, text):\n",
    "        self.text = text\n",
    "        \n",
    "    def equals(self, word2):\n",
    "        return self.text.lower() == word2.text.lower()\n",
    "\n",
    "#創建三個單字物件\n",
    "first = Word('ha')\n",
    "second = Word('HA')\n",
    "third = Word('eh')\n",
    "\n",
    "#進行比較\n",
    "first.equals(second)  #True\n",
    "first.equals(third)   #False\n",
    "\n",
    "#---------------採用特殊方法寫法\n",
    "class Word():\n",
    "    def __init__(self, text):\n",
    "        self.text = text\n",
    "    \n",
    "    def __eq__(self, word2):\n",
    "        return self.text.lower() == word2.text.lower()\n",
    "\n",
    "#創建三個單字物件\n",
    "first = Word('ha')\n",
    "second = Word('HA')\n",
    "third = Word('eh')\n",
    "\n",
    "#進行比較\n",
    "first == second  #True\n",
    "first == third   #False\n",
    "```\n",
    "\n",
    "是~不~是~漂亮許多啦!!!!\n",
    "\n",
    "一些常用的特殊用法整理如下\n",
    "\n",
    "\n",
    "### 比較用\n",
    "|方法名稱            | 使用                   |\n",
    "|:------------------:|:---------------------:|\n",
    "|\\_\\_eq\\_\\_(self, other) | self == other     |\n",
    "|\\_\\_ne\\_\\_(self, other) | self != other     |\n",
    "|\\_\\_lt\\_\\_(self, other) | self < other      |\n",
    "|\\_\\_gt\\_\\_(self, other) | self > other      |\n",
    "|\\_\\_le\\_\\_(self, other) | self <= other     |\n",
    "|\\_\\_ge\\_\\_(self, other) | self >= other     |\n",
    "\n",
    "\n",
    "### 數學用\n",
    "|方法名              | 使用                   |\n",
    "|:------------------:|:---------------------:|\n",
    "|\\_\\_add\\_\\_(self, other)|self + other       |\n",
    "|\\_\\_sub\\_\\_(self, other)|self - other       |\n",
    "|\\_\\_mul\\_\\_(self, other)|self * other       |\n",
    "|\\_\\_floordiv\\_\\_(self, other)|self // other |\n",
    "|\\_\\_truediv\\_\\_(self, other)|self / other   |\n",
    "|\\_\\_mod\\_\\_(self, other)|self % other       |\n",
    "|\\_\\_pow\\_\\_(self, other)|self ** other      |\n",
    "\n",
    "### 其他常用\n",
    "|方法名              | 使用                   |\n",
    "|:------------------:|:---------------------:|\n",
    "|\\_\\_str\\_\\_(self)|str(self)                 |\n",
    "|\\_\\_repr\\_\\_(self)|repr(self)               |\n",
    "|\\_\\_len\\_\\_(self)|len(self)                 |\n",
    "\n",
    "\n",
    "完整清單請看官方文件。\n",
    "https://docs.python.org/3/reference/datamodel.html#special-method-names"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hahaha!!\n",
      "20\n",
      "min:3,max:10\n",
      "min:3,max:10\n"
     ]
    }
   ],
   "source": [
    "class Word():\n",
    "    def __init__(self, text):\n",
    "        self.text = text\n",
    "    \n",
    "    def __str__(self):\n",
    "        return self.text + 'haha!!'\n",
    "\n",
    "class sqrtt():\n",
    "    def __init__(self, num):\n",
    "        self.num = num\n",
    "    \n",
    "    def __mul__(self, number):\n",
    "        return self.num * number.num\n",
    "    \n",
    "class minmax():\n",
    "    def __init__(self, minn, maxx):\n",
    "        self.minn = minn\n",
    "        self.maxx = maxx\n",
    "    \n",
    "    def __str__(self):\n",
    "        return 'min:' + str(self.minn) + ',max:'+ str(self.maxx)\n",
    "    \n",
    "\n",
    "#創建三個單字物件\n",
    "first = Word('ha')\n",
    "\n",
    "print(first)   #print必須為字串，所以程式自行使用str()轉換成字串\n",
    "\n",
    "XD = sqrtt(4)\n",
    "XDD = sqrtt(5)\n",
    "print( XD * XDD )\n",
    "\n",
    "AM = minmax(3, 10)\n",
    "print(AM)\n",
    "print('min:' + str(AM.minn) + ',max:'+ str(AM.maxx))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "<a id='Composition'></a>\n",
    "## 6.13 組合\n",
    "[回目錄](#HOME) \n",
    "\n",
    "\n",
    "如果要新建的類別有相似的類別可以繼承的話就可以採用繼承來取得父類別的所有，  \n",
    "但若兩個類別差異太大，或是沒有關係，我們就可以採用組合來合併這些類別\n",
    "\n",
    "例如，鴨子是鳥的一種，所以可以繼承鳥的類別，  \n",
    "但是嘴巴和尾巴不是鴨子的一種，而是鴨子的組成。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "這隻鴨子有一個 紅色的 嘴巴，然後有 白色，15cm 長的尾巴\n"
     ]
    }
   ],
   "source": [
    "\n",
    "class Bill():\n",
    "    def __init__(self, description):\n",
    "        self.description = description\n",
    "        \n",
    "class Tail():\n",
    "    def __init__(self, length):\n",
    "        self.length = length\n",
    "    \n",
    "\n",
    "class Duck():\n",
    "    def __init__(self, bill, tail):\n",
    "        self.bill = bill\n",
    "        self.tail = tail\n",
    "    def about(self):\n",
    "        print('這隻鴨子有一個', bill.description, '嘴巴，然後有', tail.length, '長的尾巴')\n",
    "\n",
    "        \n",
    "bill = Bill('紅色的')\n",
    "tail = Tail('白色，15cm')\n",
    "\n",
    "duck = Duck(bill, tail)\n",
    "duck.about()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "<a id='ClassesModules'></a>\n",
    "## 6.14 類別與對象v.s.模組\n",
    "[回目錄](#HOME)\n",
    "\n",
    "有一些方法可以幫助你決定是把你的代碼封裝到類裡還是模塊裡。\n",
    "* 當你需要許多具有相似行為（方法），但不同狀態（特性）的實例時，使用對象是最好的選擇。\n",
    "* 類支持繼承，但模塊不支持。\n",
    "* 如果你想要保證實例的唯一性，使用模塊是最好的選擇。不管模塊在程序中被引用多少次，始終只有一個實例被加載。  \n",
    "* 如果你有一系列包含多個值的變量，並且它們能作為參數傳入不同的函數，那麼最好將它們封裝到類裡面。舉個例子，你可能會使用以大小和顏色為鍵的字典代表一張\n",
    "彩色图片。你可以在程序中为每张图片创建不同的字典，并把它们作为参数传递给像規模（）或者變換（）之類的函數。但這麼做的話，一旦你想要添加其他的鍵或者函數會變得非常麻煩。為了保證統一性，應該定義一個圖片類，把大小和顏色作為特性，把規模（）和變換（）定義為方法。這麼一來，關於一張圖片的所有數據和可執行的操作都存儲在了統一的位置。\n",
    "* 用最簡單的方式解決問題。使用字典，列表和元組往往要比使用模塊更加簡單，簡潔且快速。而使用類則更為複雜。\n",
    "\n",
    "\n",
    "---\n",
    "### 命名Tuple(named tuple)\n",
    "\n",
    "可以用來創造可以用名稱訪問的Tuple子類\n",
    "\n",
    "跟Tuple一樣，不可被改變，但是可以透過替換來產生新的命名Tuple"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Duck(bill='wide orange', tail='long')\n",
      "wide orange\n",
      "long\n",
      "Duck(bill='wide orange', tail='long')\n",
      "Duck(bill='crushing', tail='magnificent')\n"
     ]
    }
   ],
   "source": [
    "from collections import namedtuple #引入函式庫\n",
    "\n",
    "Duck = namedtuple('Duck', 'bill tail') #宣告為命名Tuple，並且有bill和tail兩種名稱\n",
    "duck = Duck('wide orange', 'long')     #給值\n",
    "\n",
    "print(duck)\n",
    "print(duck.bill)\n",
    "print(duck.tail)\n",
    "\n",
    "parts = {'bill': 'wide orange', 'tail': 'long'}  #使用dictionary給值\n",
    "duck2 = Duck(**parts)\n",
    "print(duck2)\n",
    "\n",
    "duck3 = duck2._replace(tail='magnificent', bill='crushing')  #替換內容\n",
    "print(duck3)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [Root]",
   "language": "python",
   "name": "Python [Root]"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
